#include "Client.h"
#include <cstdio>

Client::Client()
{
    this->c_port = 12345;
    this->c_address = "127.0.0.1";
    this->send_num = 0;
    this->recv_num = 0;
}

void Client::set_address(char const* address)
{
    this->c_address = address;
}

void Client::set_port(int port)
{
    this->c_port = port;
}

void Client::set_download_file_name(char* const file_name)
{
    this->c_download_file_name = file_name;
}

void Client::set_output_file_name(char* const file_name)
{
    this->c_output_file_name = file_name;
}

char const* Client::get_address()
{
    return this->c_address;
}

int Client::get_port()
{
    return this->c_port;
}

int Client::create_socket()
{
    this->sockfd = socket(AF_INET, SOCK_STREAM, 0);
    return this->sockfd;
}

void Client::init_address()
{
    memset(&this->c_server_address, 0, sizeof(this->c_server_address));
    this->c_server_address.sin_family = AF_INET;
    this->c_server_address.sin_addr.s_addr = inet_addr(this->c_address);
    this->c_server_address.sin_port = htons(this->c_port);
}

int Client::connect_socket()
{
    printf("connecting to %s:%d....\n", this->c_address, this->c_port);
    int res = connect(this->sockfd, (struct sockaddr*)&(this->c_server_address), sizeof(this->c_server_address));
    return res;
}

void Client::close_sockfd()
{
    close(this->sockfd);
}

void Client::request_list()
{
    // printf("try to request file lists\n");
    std::string content("l");
    write_send_buffer(content);
    send_to_server();
    int n;
    n = read(this->sockfd, this->recv_buff, MAXLINE);
    printf("%s", this->recv_buff);
}

void Client::request_file(int is_download, int is_output)
{
    // printf("try to download file\n");
    if(!is_output)
    {
        this->c_output_file_name = this->c_download_file_name;
    }

    // check if the output file name exists
    if(!access(this->c_output_file_name, F_OK))
    {
        printf("failed to download %s: %s already exists\n", this->c_output_file_name, this->c_output_file_name);
        exit(1);
    }

    // send file name to server
    std::string content("d");
    for(int i = 0; i < strlen(this->c_download_file_name); i++)
    {
        content += this->c_download_file_name[i];
    }
    write_send_buffer(content);
    send_to_server();

    int n;
    n = read(this->sockfd, this->recv_buff, MAXLINE);
    // get the content of recv buffer
    if(this->recv_buff[0] == ' ')
    {
        printf("%s\n", this->recv_buff);
        exit(1);
    }
    else
    {
        download_file();
    }
}

void Client::write_send_buffer(std::string content)
{
    for(int i = 0; i < content.length(); i++)
    {
        this->send_buff[i] = content[i];
    }
    this->send_num = content.length();
    this->send_buff[this->send_num] = '\0';
}

void Client::send_to_server()
{
    int n;
    size_t nbytes = this->send_num * sizeof(char);
    // printf("sending request to server...\n");
    if(n = send(this->sockfd, this->send_buff, nbytes, 0) != nbytes)
    {
        printf("send %d bytes but it actually has %d bytes\n", n, (int)nbytes);
    }
}

void Client::download_file()
{
    printf("start downloading %s...\n", this->c_download_file_name);
    if((this->fq = fopen(this->c_output_file_name, "ab")) == NULL)
    {
        printf("failed to open %s\n", this->c_output_file_name);
    }
    else
    {
        fwrite(this->recv_buff, strlen(this->recv_buff) - 1, 1, this->fq);
        printf("ok %s\n", this->c_output_file_name);
    }
    fclose(this->fq);
}

void Client::print_help()
{
    printf("Usage: fclient [OPTION] ...\n");
    printf("download file from fserver over tcp\n\n");
    printf("options:\n");
    printf("    -l, --list                 show remote served files [default action]\n");
    printf("    -s, --server            specify server address [default addr is localhost]\n");
    printf("    -p, --port                 specify server port [default port is 12345]\n");
    printf("    -d, --dl=FILE              download specified file\n");
    printf("    -o, --output=FILE        output to the FILE\n");
    printf("    -h, --help                display this help and exit\n");
}